// Debug Scene Node
// (c) jimon game studio

#include "CDebugSceneNode.h"

#include "ILogManager.h"

#include "IFileSystem.h"
#include "IMeshLoader.h"

namespace je
{
	namespace scene
	{

		#define JE_DEBUG_SCENE_NODE_SHADER \
											"#ifdef VS\n\
											FIN vec4 IPosition;\n\
											FIN vec4 IColor;\n\
											FOUT vec4 Color;\n\
											uniform mat4 MVPMat;\n\
											NOLIGHT_VS_VARS\n\
											void main()\n\
											{\n\
												gl_Position = MVPMat * IPosition;\n\
												Color = IColor;\n\
												NOLIGHT_VS_MAIN\n\
											}\n\
											#endif\n\
											#ifdef FS\n\
											SIN vec4 Color;\n\
											NOLIGHT_FS_VARS\n\
											void main()\n\
											{\n\
												NOLIGHT_FS_MAIN(Color,vec3(0,0,0))\n\
											}\n\
											#endif\n"

		#define JE_DEBUG_SCENE_NODE_SHADER2 \
											"#ifdef VS\n\
											FIN vec4 IPosition;\n\
											uniform mat4 MVPMat;\n\
											NOLIGHT_VS_VARS\n\
											void main()\n\
											{\n\
												gl_Position = MVPMat * IPosition;\n\
												NOLIGHT_VS_MAIN\n\
											}\n\
											#endif\n\
											#ifdef FS\n\
											NOLIGHT_FS_VARS\n\
											void main()\n\
											{\n\
												NOLIGHT_FS_MAIN(vec4(1,1,1,1),vec3(0,0,0))\n\
											}\n\
											#endif\n"

		//! Constructor
		CDebugSceneNode::CDebugSceneNode(video::IRender * Render,scene::ISceneManager * SceneManager)
			:IDebugSceneNode(Render,"DebugSceneNode"),CurrentSceneManager(SceneManager),Op(NULL)
		{
			SetType(DSNT_DEFAULT);

			CurrentSceneManager->RegisterNodeInRenderingQueue(this,RPG_SOLID_WITHOUTLIGHTING);
		}

		//! Destructor
		CDebugSceneNode::~CDebugSceneNode()
		{
			CurrentSceneManager->UnRegisterNodeFromRenderingQueue(this,RPG_SOLID_WITHOUTLIGHTING);

			JEDELETE(Mat)
			if(Op)
				Op->Drop();
		}

		//! Set Type
		void CDebugSceneNode::SetType(DebugSceneNodeType Type)
		{
			if(Op)
				switch(CurrentType)
				{
				case DSNT_DEFAULT:
				case DSNT_GRID:
					{
						JEDELETE(Mat)
						JEDELETE(Op)
						Op = NULL;
						break;
					}
				}

			switch(Type)
			{
			case DSNT_DEFAULT:
				{
					jeVector3df Vt[4];
					Vt[0].SetXYZ(0,0,0);
					Vt[1].SetXYZ(1,0,0);
					Vt[2].SetXYZ(0,1,0);
					Vt[3].SetXYZ(0,0,1);

					video::jeColorARGB32f Vc[4];
					Vc[0].SetColor(1,1,1,1);
					Vc[1].SetColor(1,1,0,0);
					Vc[2].SetColor(1,0,1,0);
					Vc[3].SetColor(1,0,0,1);

					video::IHardwareBuffer * VB = CurrentRender->CreateHardwareBuffer(video::G3DT_VERTEX);
					VB->Lock(core::BLT_WRITE);
					VB->Allocate((sizeof(jeVector3df)+sizeof(video::jeColorARGB32f))*4);
					VB->Write(Vt,sizeof(jeVector3df)*4);
					VB->Merge(Vc,4*sizeof(video::jeColorARGB32f),sizeof(video::jeColorARGB32f),sizeof(jeVector3df)+sizeof(video::jeColorARGB32f));
					VB->UnLock();

					u16 It[6] = {0,1,0,2,0,3};
					video::IHardwareBuffer * IB = CurrentRender->CreateHardwareBuffer(video::G3DT_INDEX);
					IB->Lock(core::BLT_WRITE);
					IB->Allocate(sizeof(u16)*6);
					IB->Write(It,sizeof(u16)*6);
					IB->UnLock();

					video::IHardwareBufferArray * Array = CurrentRender->CreateHardwareBufferArray();
					Array->AttachBuffer(VB,video::HBAL_POSITION,3,4,3*4+4*4);
					Array->AttachBuffer(VB,video::HBAL_COLOR,4,4,3*4+4*4,sizeof(jeVector3df));
					Array->AttachBuffer(IB,video::HBAL_INDEXES,1,2);
					VB->Drop();
					IB->Drop();

					JENEW(Op,video::jeRenderOperation_Draw)
					Op->SetArray(Array);
					Array->Drop();

					JENEW(Mat,video::jeMaterial)

					video::IShaderMaterial * SM = CurrentRender->CreateShaderMaterial(JE_DEBUG_SCENE_NODE_SHADER);
					Mat->SetShaderMaterial(SM);
					SM->Drop();

					break;
				}
			case DSNT_GRID:
				{
					s32 Size = 17;
					s32 BlockSize = 1;

					jeVector3df * Vt = NULL;
					JENEW_A(Vt,jeVector3df,Size*2*2)
					f32 Corr = -(f32)Size*BlockSize/2.0f;
					for(s32 i=0;i<Size;i++)
					{
						Vt[i*4+0].SetXYZ(Corr,0,(f32)i*BlockSize+Corr);
						Vt[i*4+1].SetXYZ((f32)(Size-1)*BlockSize+Corr,0,(f32)i*BlockSize+Corr);
						Vt[i*4+2].SetXYZ((f32)i*BlockSize+Corr,0,Corr);
						Vt[i*4+3].SetXYZ((f32)i*BlockSize+Corr,0,(f32)(Size-1)*BlockSize+Corr);
					}

					video::IHardwareBuffer * VB = CurrentRender->CreateHardwareBuffer(video::G3DT_VERTEX);
					VB->Lock(core::BLT_WRITE);
					VB->Allocate(sizeof(jeVector3df)*Size*2*2);
					VB->Write(Vt,sizeof(jeVector3df)*Size*2*2);
					VB->UnLock();
					JEDELETE_A(Vt)

					u16 * It = NULL;
					JENEW_A(It,u16,Size*2*2)
					for(s32 i=0;i<Size*2*2;i++)
						It[i] = i;
					video::IHardwareBuffer * IB = CurrentRender->CreateHardwareBuffer(video::G3DT_INDEX);
					IB->Lock(core::BLT_WRITE);
					IB->Allocate(sizeof(u16)*Size*2*2);
					IB->Write(It,sizeof(u16)*Size*2*2);
					IB->UnLock();
					JEDELETE_A(It)

					video::IHardwareBufferArray * Array = CurrentRender->CreateHardwareBufferArray();
					Array->AttachBuffer(VB,video::HBAL_POSITION,3,4);
					Array->AttachBuffer(IB,video::HBAL_INDEXES,1,2);
					VB->Drop();
					IB->Drop();

					JENEW(Op,video::jeRenderOperation_Draw)
					Op->SetArray(Array);
					Array->Drop();

					JENEW(Mat,video::jeMaterial)

					video::IShaderMaterial * SM = CurrentRender->CreateShaderMaterial(JE_DEBUG_SCENE_NODE_SHADER2);
					Mat->SetShaderMaterial(SM);
					SM->Drop();
					break;
				}
			}

			CurrentType = Type;
		}

		//! On Update
		void CDebugSceneNode::OnUpdate()
		{
			ISceneNode::OnUpdate();
		}

		//! On Render
		void CDebugSceneNode::OnRender()
		{
			CurrentRender->SetMaterial(Mat);
			CurrentRender->SetMatrix(AbsoluteModelMatrix,video::RMT_MODEL);
			CurrentRender->RenderOperation(video::ROT_DRAW_LINES,Op);
			ISceneNode::OnRender();
		}

		//! Serialize
		void CDebugSceneNode::Serialize(core::ISerializeStream * SerializeStream)
		{
			JE_SS_BEGIN(DebugSceneNode)
			JE_SS_ENUM(CurrentType,DebugSceneNodeType)
			JE_SS_END(DebugSceneNode)

			if(JE_SS_LOAD)
				SetType(CurrentType);

			ISceneNode::Serialize(SerializeStream);
		}
	}
}
